package health_system.health_system.websocket;

import org.springframework.util.StringUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 文件传输工具类
 * 处理WebSocket中的文件和多媒体传输
 */
public class FileTransferUtils {
    private static final Logger logger = Logger.getLogger(FileTransferUtils.class.getName());
    
    // 允许的文件类型映射
    private static final Map<String, String> ALLOWED_MIME_TYPES = new HashMap<>();
    
    // 媒体内容类型和文件扩展名映射
    private static final Map<String, String> CONTENT_TYPE_EXTENSIONS = new HashMap<>();
    
    // 分块传输缓存（messageId -> Map<chunkIndex, chunkData>）
    private static final Map<String, Map<Integer, String>> chunkTransfers = new ConcurrentHashMap<>();
    
    // 常量定义
    private static final String MEDIA_ROOT_PATH = "media";
    private static final int MAX_CHUNK_SIZE = 1024 * 1024; // 1MB
    private static final long MAX_TOTAL_FILE_SIZE = 100 * 1024 * 1024; // 100MB
    
    static {
        // 初始化允许的MIME类型映射
        ALLOWED_MIME_TYPES.put("image/jpeg", ".jpg");
        ALLOWED_MIME_TYPES.put("image/png", ".png");
        ALLOWED_MIME_TYPES.put("image/gif", ".gif");
        ALLOWED_MIME_TYPES.put("image/webp", ".webp");
        ALLOWED_MIME_TYPES.put("video/mp4", ".mp4");
        ALLOWED_MIME_TYPES.put("video/webm", ".webm");
        ALLOWED_MIME_TYPES.put("audio/mp3", ".mp3");
        ALLOWED_MIME_TYPES.put("audio/wav", ".wav");
        ALLOWED_MIME_TYPES.put("audio/ogg", ".ogg");
        ALLOWED_MIME_TYPES.put("application/pdf", ".pdf");
        ALLOWED_MIME_TYPES.put("application/msword", ".doc");
        ALLOWED_MIME_TYPES.put("application/vnd.openxmlformats-officedocument.wordprocessingml.document", ".docx");
        ALLOWED_MIME_TYPES.put("application/vnd.ms-excel", ".xls");
        ALLOWED_MIME_TYPES.put("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ".xlsx");
        
        // 初始化内容类型和文件扩展名的映射
        CONTENT_TYPE_EXTENSIONS.put("image", ".jpg");
        CONTENT_TYPE_EXTENSIONS.put("video", ".mp4");
        CONTENT_TYPE_EXTENSIONS.put("audio", ".mp3");
        CONTENT_TYPE_EXTENSIONS.put("file", ".bin");
    }
    
    /**
     * 处理并保存社交媒体文件（朋友圈、头像等）
     * 
     * @param userId 用户ID
     * @param contentType 内容类型
     * @param base64Data Base64编码的文件数据
     * @param fileName 文件名（可选）
     * @return 文件URL
     * @throws IOException 如果文件处理失败
     */
    public static String processSocialMediaFile(String userId, String contentType, String base64Data, String fileName) throws IOException {
        if (base64Data == null || base64Data.isEmpty()) {
            throw new IllegalArgumentException("文件数据不能为空");
        }
        
        // 从Base64字符串中提取MIME类型（如果有）
        String mimeType = extractMimeType(base64Data);
        String decodedData = removeBase64Header(base64Data);
        
        // 验证MIME类型
        if (mimeType != null && !ALLOWED_MIME_TYPES.containsKey(mimeType)) {
            throw new IllegalArgumentException("不支持的媒体类型: " + mimeType);
        }
        
        // 生成文件扩展名
        String extension;
        if (mimeType != null) {
            extension = ALLOWED_MIME_TYPES.get(mimeType);
        } else if (CONTENT_TYPE_EXTENSIONS.containsKey(contentType)) {
            extension = CONTENT_TYPE_EXTENSIONS.get(contentType);
        } else if (fileName != null && fileName.contains(".")) {
            extension = fileName.substring(fileName.lastIndexOf("."));
        } else {
            extension = ".bin";
        }
        
        // 生成唯一文件名
        String uniqueFileName = generateUniqueFileName(userId, extension);
        
        // 创建存储目录
        String relativePath = createMediaDirectory(userId, contentType);
        
        // 存储文件
        byte[] fileData = Base64.getDecoder().decode(decodedData);
        
        // 检查文件大小
        if (fileData.length > MAX_TOTAL_FILE_SIZE) {
            throw new IllegalArgumentException("文件大小超过限制");
        }
        
        // 保存文件
        String filePath = relativePath + File.separator + uniqueFileName;
        saveFile(fileData, filePath);
        
        // 返回文件的相对URL
        return "/" + MEDIA_ROOT_PATH + "/" + contentType + "/" + userId + "/" + uniqueFileName;
    }
    
    /**
     * 处理分块文件传输
     * 
     * @param messageId 消息ID
     * @param chunkIndex 当前块索引
     * @param totalChunks 总块数
     * @param chunkData 当前块的Base64编码数据
     * @return 如果所有块都已接收，则返回合并后的数据；否则返回null
     */
    public static String processChunkedFile(String messageId, int chunkIndex, int totalChunks, String chunkData) {
        // 初始化消息的分块映射
        Map<Integer, String> chunks = chunkTransfers.computeIfAbsent(messageId, k -> new ConcurrentHashMap<>());
        
        // 存储当前分块
        chunks.put(chunkIndex, chunkData);
        
        // 检查是否收到了所有分块
        if (chunks.size() == totalChunks) {
            // 合并所有分块
            StringBuilder completeData = new StringBuilder();
            for (int i = 0; i < totalChunks; i++) {
                String chunk = chunks.get(i);
                if (chunk == null) {
                    // 缺少某个分块，无法完成合并
                    return null;
                }
                completeData.append(chunk);
            }
            
            // 清理缓存
            chunkTransfers.remove(messageId);
            
            // 返回完整数据
            return completeData.toString();
        }
        
        // 尚未收到所有分块
        return null;
    }
    
    /**
     * 清理指定消息ID的所有分块数据
     * 
     * @param messageId 消息ID
     */
    public static void clearChunks(String messageId) {
        chunkTransfers.remove(messageId);
    }
    
    /**
     * 将文件拆分为多个分块进行传输
     * 
     * @param fileData 文件二进制数据
     * @return 分块数组，每个元素是一个Base64编码的字符串
     */
    public static String[] splitFileIntoChunks(byte[] fileData) {
        if (fileData == null || fileData.length == 0) {
            return new String[0];
        }
        
        int totalChunks = (int) Math.ceil((double) fileData.length / MAX_CHUNK_SIZE);
        String[] chunks = new String[totalChunks];
        
        for (int i = 0; i < totalChunks; i++) {
            int start = i * MAX_CHUNK_SIZE;
            int end = Math.min(start + MAX_CHUNK_SIZE, fileData.length);
            int length = end - start;
            
            byte[] chunkData = new byte[length];
            System.arraycopy(fileData, start, chunkData, 0, length);
            
            chunks[i] = Base64.getEncoder().encodeToString(chunkData);
        }
        
        return chunks;
    }
    
    /**
     * 从Base64字符串中提取MIME类型
     * 
     * @param base64Data Base64编码的数据
     * @return MIME类型，如果未找到则返回null
     */
    private static String extractMimeType(String base64Data) {
        if (base64Data == null || !base64Data.startsWith("data:")) {
            return null;
        }
        
        int commaIndex = base64Data.indexOf(",");
        if (commaIndex == -1) {
            return null;
        }
        
        String header = base64Data.substring(0, commaIndex);
        int colonIndex = header.indexOf(":");
        int semicolonIndex = header.indexOf(";");
        
        if (colonIndex != -1 && semicolonIndex != -1) {
            return header.substring(colonIndex + 1, semicolonIndex);
        }
        
        return null;
    }
    
    /**
     * 移除Base64数据的头部信息
     * 
     * @param base64Data Base64编码的数据
     * @return 移除头部后的Base64数据
     */
    private static String removeBase64Header(String base64Data) {
        if (base64Data == null) {
            return "";
        }
        
        int commaIndex = base64Data.indexOf(",");
        if (commaIndex != -1 && base64Data.startsWith("data:")) {
            return base64Data.substring(commaIndex + 1);
        }
        
        return base64Data;
    }
    
    /**
     * 生成唯一文件名
     * 
     * @param userId 用户ID
     * @param extension 文件扩展名
     * @return 唯一文件名
     */
    private static String generateUniqueFileName(String userId, String extension) {
        String timestamp = String.valueOf(System.currentTimeMillis());
        String uuid = UUID.randomUUID().toString().substring(0, 8);
        
        return timestamp + "_" + uuid + extension;
    }
    
    /**
     * 创建媒体文件存储目录
     * 
     * @param userId 用户ID
     * @param contentType 内容类型
     * @return 创建的目录路径
     * @throws IOException 如果目录创建失败
     */
    private static String createMediaDirectory(String userId, String contentType) throws IOException {
        String relativePath = MEDIA_ROOT_PATH + File.separator + contentType + File.separator + userId;
        Path dirPath = Paths.get(relativePath);
        
        if (!Files.exists(dirPath)) {
            Files.createDirectories(dirPath);
        }
        
        return relativePath;
    }
    
    /**
     * 保存文件到指定路径
     * 
     * @param fileData 文件数据
     * @param filePath 文件路径
     * @throws IOException 如果保存失败
     */
    private static void saveFile(byte[] fileData, String filePath) throws IOException {
        try (FileOutputStream fos = new FileOutputStream(filePath)) {
            fos.write(fileData);
            fos.flush();
        }
        logger.info("文件已保存至: " + filePath);
    }
    
    /**
     * 验证文件类型是否允许
     * 
     * @param mimeType MIME类型
     * @return 如果允许则返回true，否则返回false
     */
    public static boolean isAllowedFileType(String mimeType) {
        return mimeType != null && ALLOWED_MIME_TYPES.containsKey(mimeType);
    }
    
    /**
     * 获取指定contentType的默认文件扩展名
     * 
     * @param contentType 内容类型
     * @return 默认文件扩展名
     */
    public static String getDefaultExtension(String contentType) {
        return CONTENT_TYPE_EXTENSIONS.getOrDefault(contentType, ".bin");
    }
} 